<?php

namespace app\api\controller;

use app\common\model\MemberFile;
use app\common\model\PushLog;
use app\common\model\PushPlan;
use app\common\model\SiteDemo;
use DOMDocument;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use hg\apidoc\annotation as Apidoc;
use hg\apidoc\annotation\Param;
use hg\apidoc\annotation\Query;
use hg\apidoc\annotation\Returned;
use hg\apidoc\annotation\Header;
use app\BaseController;
use Symfony\Contracts\Cache;
use think\exception\ValidateException;
use think\facade\View;
use think\facade\Db;
use think\response\Json;
use ZipArchive;
/**
 * 图片分类
 *
 * admin-ImgClass
 *
 * @Apidoc\Title("站点管理")
 * @Apidoc\Group("api")
 */
class Site extends Auth
{

    /**
     * list
     * @Apidoc\Title("列表")
     */
    public function list(): \think\response\Json
    {
        $list_rows = input('list_rows', 100, 'intval');
        $where = [];

        $where[] = ['member_id', '=', $this->request->uid];
        $res = \app\common\model\Site::where($where)->order("id desc")->paginate($list_rows);
        $res = $res->toArray();
        foreach ($res['data'] as $i => $v) {
            $v['isActive']= 0;
            $v['link_count']= Db::name("site_link")->where("site_id","=",$v['id'])->count();
            $v['url'] =   ($v['$is_https'] ? 'https://' : 'http://') . $v['website'] ;
            $v['today_quantity']=Db::name("push_log")->where([
                ["site_id","=",$v['id']],
                ["create_time","between",[strtotime(date("Y-m-d 00:00:00")),strtotime(date("Y-m-d 23:59:59"))]],
            ])->count();
            $v['yesterday_quantity']=Db::name("push_log")->where([
                ["site_id","=",$v['id']],
                ["create_time","between",[strtotime(date('Y-m-d', strtotime('-1 day')).' 00:00:00'),strtotime(date('Y-m-d', strtotime('-1 day')).' 23:59:59')]],   
                ])->count();
            $v['cumulative_quantity']=Db::name("push_log")->where([
                ["site_id","=",$v['id']],  
                ])->count();            
            $res['data'][$i] = $v;
        }
        return success('ok', $res);
    }

    private function url_exists($url) {
        $ch = curl_init($url);
        //模拟蜘蛛访问，防止有的站点返回403禁止访问
        $userAgent = 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)';
        curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        if ($http_code === 200) {
            // 请求成功，返回true
            return true;
        } else {
            // 请求失败，返回错误信息
            return $error;
        }
    }


    /**
     * url_is_normal
     * @return Json
     * @Apidoc\Param("url")
     * @Apidoc\Title("网址能否正常访问")
     */
    public function urlIsNormal(): Json
    {
        $url = input('url');
        return success('', $this->url_exists($url)?'1' : '-1');
    }

    /**
     * checkVersion
     * @return Json
     * @Apidoc\Param("id")
     * @Apidoc\Title("客户网站接口检测检测")
     * @Apidoc\Returned("version", desc="版本号")
     * @Apidoc\Returned("version_status", desc="版本状态 last(最新版不需要升级) old(需要升级) original(原始版本的接口需要手动升级为) original2(原始接口获取版本的接口请求返回错误 需要用户手动升级) diy_site(自定义站点无法在线升级)")
     */
    public function checkVersion(): Json
    {
        $id = input('id');
        $site=\app\common\model\Site::find($id);
        //自定义站点不支持版本检测
        if($site['site_demo_id']==7){
            return success('ok', ['version_status'=>'diy_site','version'=>'']);
        }
        $site_demo=Db::name("site_demo")->find($site['site_demo_id']);
        //校验版本号
        $url = $site['website'] . $site_demo['version_verification_interface'];
        $split_flag = '?';
        if(strpos($url,'?')!==false){
            $split_flag = '&';
        }
        $url = ($site['is_https'] ? 'https://' : 'http://') . $url .$split_flag  .'key=' . $site['secret_key']."&rand=".rand(1,999);
        try {
            $res = (new Client([
                'verify' => false, // 禁用SSL验证
            ]))->post($url);
            $res = $res->getBody()->getContents();
            $res= json_decode($res, true);
            $version=trim($res['version']);
            //找到版本号了
            if($version){
                if($version==$site_demo['version']){
                    return success('最新版本', ['version_status'=>'last','version'=>$version]);
                }elseif($version=="no_upgrade"){
                    return success('在接口文件里定义了no_upgrade，禁止在线升级', ['version_status'=>'no_upgrade','version'=>$version]);
                }else{
                    return success('需要升级', ['version_status'=>'old','version'=>$version]);
                }
            }else if($res['status']=="0"){
                return success($res['msg'], ['version_status'=>'error','version'=>$res['msg']]);
            }else{
                //未找到，证明是老的api接口
                return success('未发现版本号，可能是老的api接口需要手动升级', ['version_status'=>'original','version'=>'']);
            }
        } catch (RequestException $e) {
            return success('ok', ['version_status'=>'error','version'=>'']);
        }
    }
    /**
     * updatePlus
     * @return Json
     * @Apidoc\Param("site_id")
     * @Apidoc\Title("升级站点接口")
     */
    public function updatePlus(): Json
    {
        $site_id= input('site_id',0,"intval");
        if(!$site_id){
            return error("缺少site_id参数");
        }
        $site=\app\common\model\Site::where([
            ["id","=",$site_id],
            ["member_id","=",$this->request->uid],
        ])->find();
        if(!$site){
            return error("站点不存在");
        }    
        $site_demo=Db::name("site_demo")->find($site['site_demo_id']);
        if(!$site_demo){
            return error("升级系统不存在当前站点系统");
        }  
        //校验版本号
        $url = $site['website'] . $site_demo['version_upgrade_interface'];
        $split_flag = '?';
        if(strpos($url,'?')!==false){
            $split_flag = '&';
        }
        $url = ($site['is_https'] ? 'https://' : 'http://') . $url .$split_flag  .'key=' . $site['secret_key'].'&site_id=' . $site_id;        
        try {
            $res = (new Client([
                'verify' => false, // 禁用SSL验证
            ]))->get($url);
            $res = $res->getBody()->getContents();
            $res= json_decode($res, true);
            if($res['status']){
                return success('升级成功');
            }else{
                return error("fail".$res["msg"]."请点击[编辑]重新下载插件来手动升级",$res);
            }
        } catch (RequestException $e) {
            return error("升级失败：网络错误或程序异常，请手动在浏览器里执行升级url：".$url);
        }
    }
    /**
     * listDemo
     *  @Apidoc\Title("demo列表")
     */
    public function listDemo()
    {
        $res = SiteDemo::field('id, name, logo_image')->order("sort asc,id asc")->select();
        return success('ok', $res);
    }


    /**
     * getDemoById
     * @Apidoc\Title("根据id获取demo详情")
     */
    public function getDemo()
    {
        $res = SiteDemo::find(input('id'));
        return success('ok', $res);
    }





    /**
     * @Apidoc\Title("新增or更新（是否有id）")
     * @Apidoc\Method("post")
     */
    public function add()
    {
        $data = request()->post(['id','article_content_field', 'column_field','column_interface','cookies','create_time_field','headers','name','other_fields','publish_success_flag','publishing_interface','thumbnail_field','title_field', 'website','is_https','secret_key','site_demo_id','tags_field','keywords_field','description_length','description_field']);
        $data['website']=trim($data['website']);
        validate([
            'name|站点名称' => 'require',
            'column_interface|栏目接口地址' => 'require',
            'website|网站地址' => 'require',
            'publishing_interface|发布接口地址' => 'require',
            'title_field|文章标题字段' => 'require',
            'column_field|文章栏目字段' => 'require',
//            'thumbnail_field|缩略图字段' => 'require',
//            'create_time_field|文章时间字段' => 'require',
            'article_content_field|文章内容字段' => 'require',
//            'publish_success_flag|发布成功标志' => 'require',
        ])->check($data);

        $url =  ($data['is_https'] ? 'https://' : 'http://') . $data['website'] ;
        $urlCheck=$this->url_exists($url);
        if(!$urlCheck) {
            throw new ValidateException($url.'访问错误' .$urlCheck );
        }

        $testClass = $this->testClassesByUrl($data['website'] . $data['column_interface'], $data['is_https'], $data['secret_key']);
        if(!$testClass[0]){
            $result=$testClass[1];
            $resultJson= json_decode($result);
            if($resultJson){
                $str= json_encode($resultJson,JSON_UNESCAPED_UNICODE);
            }else{
                $str=$result;
            }
            throw new ValidateException('网站栏目接口地址访问错误:'. $str);
        }


        $data['member_id'] = $this->request->uid;
        $id = 0;
        if($data['id']) {
            \app\common\model\Site::update($data);
            $id = $data['id'];

        }else{
            $site = \app\common\model\Site::create($data);
            $id = $site->id;
            //如果有传递关键词
            $keywords=input("keywords");
            if($keywords){
                foreach($keywords as $keyword){
                    $url=($data['is_https']?"https://":"http://").$data['website'];
                    \app\common\model\SiteLink::create([
                        "site_id"=>$id,
                        "name"=>$keyword,
                        "url"=>$url,
                        "member_id"=>$data['member_id'],
                    ]);
                }
            }
        }
        return success('', ['id' => $id]);
    }
    /**
     * @Apidoc\title("查询关键词库")
     * @Apidoc\Method("get")
     */
    public function showKeywordsLibrary(){
        $res = \app\common\model\Site::field("keywords_library")->find(input('site_id'));
        return success('', ['keywords_library'=> $res['keywords_library']]);
    }
    /**
     * @Apidoc\Title("设置关键词库")
     * @Apidoc\Method("post")
     */
    public function setKeywordsLibrary(){
        $data=[];
        $data['id']=input('site_id');
        $data['keywords_library']=input('keywords_library');
        $data['keywords_library']=str_replace(['，','。','|',"\n","\r\n","\r"],',',$data['keywords_library']);
        \app\common\model\Site::update($data);
        return success('');
    }
    /**
     * getSite
     * @Apidoc\Title("获取站点信息")
     */
    public function getSite(): Json
    {

        $site = \app\common\model\Site::find(input('id'));
        if($site['member_id'] != $this->request->uid) {
            return error('非法请求');
        }

        $fields = ['id','article_content_field', 'column_field','column_interface','create_time_field','headers','name','other_fields','publish_success_flag','publishing_interface','thumbnail_field','title_field', 'website','is_https','secret_key','site_demo_id','tags_field','keywords_field','description_length','description_field'];
        $res = \app\common\model\Site::field($fields)->where('id', input('id'))->find();
        if($res['member_id'] != $this->request->id) {
            return error('非法请求，改站点不属于你');
        }
        return success('', $res);
    }



    /**
     * delete
     * @Apidoc\Method("post")
     * @Param("id", type="int", desc="id",require=true)
     * @Apidoc\Title("删除")
     */
    public function delete()
    {
        $id = input('id');
        $site = \app\common\model\Site::find($id);
        if($site['member_id'] != $this->request->uid) {
            return error('非法请求');
        }
        $count = PushPlan::where('site_id', $id)->count();
        if($count > 0) {
            return error('该站点有'. $count .'个发布计划，暂时无法删除！');
        }
        \app\common\model\Site::destroy($id);
        return success();
    }


    /**
     * update
     * @Apidoc\Title("修改")
     * @Param("id", type="int", desc="id",require=true)
     * @Apidoc\Method("post")
     */
    public function update()
    {
        $data = request()->post(['id', 'name', 'sort']);
        validate([
            'name|名称' => 'require',
            'id|id' => 'require',
        ])->check($data);
        $site = \app\common\model\Site::find($data['id']);
        if($site['member_id'] != $this->request->uid) {
            return error('非法请求');
        }
        \app\common\model\Site::update($data);
        return success($data);
    }
    /**
     * getClassesById
     * @Apidoc\Title("根据网站id获取栏目信息")
     */
    public function getClassesById(): Json
    {
        $site = \app\common\model\Site::find(input('id'));
        if($site['member_id'] != $this->request->uid) {
            return error('非法请求');
        }
        $url = $site['website'] . $site['column_interface'];

        $split_flag = '?';
        if(strpos($url,'?')!==false){
            $split_flag = '&';
        }
        $url = ($site['is_https'] ? 'https://' : 'http://') . $url .$split_flag  .'key=' . $site['secret_key'];

        $res = (new Client([
            'verify' => false, // 禁用SSL验证
        ]))->get($url);
        $res = $res->getBody()->getContents();
        $res = $this->extractSelectOptions($res);
        $result = [];
        foreach ($res as $key => $val) {
            $result[] = [
                'id' => intval($val['value']),
                'name' => $val['label']
            ];
        }
        return success('ok', $result);
    }

    /**
     * getClassesByUrl
     * @Apidoc\Title("根据网站url获取栏目信息")
     */
    public function getClassesByUrl(): Json
    {
        $url = input('url','', 'trim');
        try{
            $res = (new Client([
                'verify' => false, // 禁用SSL验证
            ]))->get($url);
            $res = $res->getBody()->getContents();
            $res = $this->extractSelectOptions($res);
            $result = [];
            foreach ($res as $key => $val) {
                $result[] = [
                    'id' => intval($val['value']),
                    'name' => $val['label']
                ];
            }
            return success('ok', $result);
        } catch (\Exception $e){
            return error('',$e->getMessage());
        }

    }
    private function testClassesByUrl($url, $is_https, $key)
    {

        $split_flag = '?';
        if(strpos($url,'?')!==false){
            $split_flag = '&';
        }
        $url = ($is_https ? 'https://' : 'http://') . $url .$split_flag . 'key=' . $key;
        try{
            $res = (new Client([
                'verify' => false, // 禁用SSL验证
            ]))->get($url);
            $res = $res->getBody()->getContents();
            if(strpos($res, 'select')===false) {
                return [false, $res];
            }
            return [true,''];
        } catch (\Exception $e){
            return [false, $e->getMessage()];
        }
    }




    /**
     * testPush
     * @Apidoc\Title("网站测试")
     */
    public function testPush()
    {
        $site = input('site');
        $data = input('data');
        //设置站点其它字段为用户提交时填写的其它字段
        $site['other_fields']=$data['other_fields'];
        //实例化发布服务
        $s=new \app\api\service\ArticlePushService([]);
        //设置站点数据，目标栏目数据，测试的文章数据
        $s->site=$site;
        $s->site_cat_id=$data['catid'];
        $s->article=[
            "name"=>$data['title'],
            "keywords"=>$data['keywords'],
            "content"=>$data['content'],
        ];
        $s->picture=$data['thumb'];
        //构造数据格式
        $pushParam=$s->getPushFormData();
        //获取结果
        $result=$s->push($pushParam);
        if($result['status']){
            return success(1,[
                'body' => json_encode([
                    "status"=>$result['status'],
                    "msg"=>$result['msg'],
                    "url"=>$result['article_url'],
                ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                'header' => json_encode($result['headers']),
                'form_params' => $pushParam['data'],
            ]);
        }else{
            return success(0, [
                'body'=>$result['msg'],
                'header'=>json_encode($result['headers']),
                'form_params' => $pushParam['data'],
            ]);       
        }    
    }
    //提取栏目里的select标签
    private function extractSelectOptions($html) {
        $html = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>' . $html;
        $dom = new DOMDocument();
        $dom->loadHTML($html);

        $options = [];
        $selectTags = $dom->getElementsByTagName('select');

        foreach ($selectTags as $selectTag) {
            $optionTags = $selectTag->getElementsByTagName('option');
            foreach ($optionTags as $optionTag) {
                $value = $optionTag->getAttribute('value');
                $label = $optionTag->nodeValue;
                $options[] = ['value' => $value, 'label' => $label];
            }
        }

        return $options;
    }

   /**
     * downloadPlus
     * @Apidoc\Title("下载网站接口")
     */
    public function downloadPlus()
    {
        $site_id= input('site_id',0,"intval");
        $site_demo_id= input('site_demo_id',0,"intval");
        $key= input('key',"","trim");
        if(!$key){
            return error("请生成接口密码");
        }   
        if($site_id){
            $site=\app\common\model\Site::where([
                ["id","=",$site_id],
                ["member_id","=",$this->request->uid],
            ])->find();
            if(!$site){
                return error("站点不存在");
            }  
            $site_demo_id=$site['site_demo_id'];
        }
        $site_demo=Db::name("site_demo")->find($site_demo_id);
        if(!$site_demo){
            return error("升级系统不存在当前站点系统");
        } 
        //获取文件的真实路径
        $parsedUrl = parse_url($site_demo['interface_file']);//由于站点文件存放的路径结构是http://wxxx.com/down/1.zip这样的，需要去掉域名部分提取down/1.zip
        // 获取文件相对路径部分
        $interface_file = isset($parsedUrl['path']) ? $parsedUrl['path'] : '';
        // 删除可能的多个斜杠，并输出结果
        $interface_file = ltrim($interface_file, '/');        
        // 指定原始zip文件路径和目标zip文件路径
        $sourceZipPath = app()->getRootPath().'public/'.$interface_file;//获取文件在服务器上的具体位置
        $rand_file_name='site_demo_id_'.$site_demo_id."_".date("YmdHis"). '.zip';
        $destinationZipPath = app()->getRootPath().'public/storage/tmp/'.$rand_file_name;//设置一个临时文件    
        $downloadFile =config('wechat.base_url').'/storage/tmp/'.$rand_file_name;//返回给客户端下载的文件
        
        $zip = new ZipArchive;
        if ($zip->open($sourceZipPath) === TRUE) {
            // 创建一个临时文件夹用于解压
            $tempDir = app()->getRootPath().'public/storage/tmp/site_plus_tmp_' . time();
            mkdir($tempDir);
            // 解压原始zip文件
            $zip->extractTo($tempDir);
            // 关闭zip文件
            $zip->close();
            // 遍历临时文件夹中的文件，并替换内容
            $this->recursiveReplace($tempDir, '{aidogkey}',$key);
            // 创建目标zip文件并压缩临时文件夹
            $destinationZip = new ZipArchive;
            if ($destinationZip->open($destinationZipPath, ZipArchive::CREATE) === TRUE) {
                // 递归添加文件到目标zip文件中，保持原始结构
                $this->recursiveZip($tempDir, $destinationZip, '');
                // 关闭目标zip文件
                $destinationZip->close();
            }
            // 删除临时文件夹
            $this->removeDirectory($tempDir);

            // 提供下载链接
            if (file_exists($destinationZipPath)) {
                return success("请求成功",$downloadFile);
            } else {
                return error("无法创建接口文件");
            }
        } else {
            return error("文件不存在或者打开错误,请联系右侧咨询客服");
        }
    }

    // 递归替换文件中的内容
    private function recursiveReplace($dir, $search, $replace)
    {
        $files = scandir($dir);
        foreach ($files as $file) {
            if ($file === '.' || $file === '..') continue;
            $filePath = $dir . DIRECTORY_SEPARATOR . $file;
            if (is_dir($filePath)) {
                $this->recursiveReplace($filePath, $search, $replace);
            } else {
                $fileContent = file_get_contents($filePath);
                $fileContent = str_replace($search, $replace, $fileContent);
                file_put_contents($filePath, $fileContent);
            }
        }
    }

    // 递归添加文件到目标zip文件中，保持原始结构
    private function recursiveZip($dir, &$zip, $parentDir)
    {
        $files = scandir($dir);
        foreach ($files as $file) {
            if ($file === '.' || $file === '..') continue;
            $filePath = $dir . DIRECTORY_SEPARATOR . $file;
            $relativePath = $parentDir . '/' . $file;
            if (is_dir($filePath)) {
                // 递归添加子文件夹中的文件到目标zip文件中
                $this->recursiveZip($filePath, $zip, $relativePath);
            } else {
                $zip->addFile($filePath, $relativePath);
            }
        }
    }

    // 递归删除目录
    private function removeDirectory($dir)
    {
        if (is_dir($dir)) {
            $objects = scandir($dir);
            foreach ($objects as $object) {
                if ($object != "." && $object != "..") {
                    if (is_dir($dir . "/" . $object))
                        $this->removeDirectory($dir . "/" . $object);
                    else
                        unlink($dir . "/" . $object);
                }
            }
            rmdir($dir);
        }
    }
}
